#pragma once

#include "Utils.h"
#include <qlist.h>

enum class texType
{
	PUR = 0,
	CKB,
	TEG
};

class texture
{
public:
	QString name;
	texType type;
	virtual vec value(const vec2& uv, const hitInfo& hi, const Ray& ray)const = 0;
};


class pureColor : public texture
{
public:
	vec color;
	pureColor(QString name, vec color = vec(0.8, 0.8, 0.8)) :color(color) { this->name = name; type = texType::PUR; }
	pureColor(QString name, QColor color) :color(color2vec(color)) { this->name = name; type = texType::PUR; }

	vec value(const vec2& uv, const hitInfo& hi, const Ray& ray)const
	{
		return color;
	}
};

class checkBox : public texture
{
public:
	vec color;
	vec darkColor;
	vec scale;
	int dir;
	bool contrast;
	checkBox(QString name, vec color, vec darkColor,vec scale = vec(2,2,2), int dir = 0, bool contrast = true) :
		color(color), darkColor(darkColor), scale(scale), dir(dir), contrast(contrast) {
		this->name = name; type = texType::CKB;
	}
	checkBox(QString name, QColor color, QColor darkColor, vec scale = vec(2,2,2), int dir = 0, bool contrast = true) :
		color(color2vec(color)), darkColor(color2vec(darkColor)), scale(scale), dir(dir), contrast(contrast) {
		this->name = name; type = texType::CKB;
	}
	vec value(const vec2& uv, const hitInfo& hi, const Ray& ray)const
	{
		float lum0 = 0, lum1 = 0;
		switch (dir)
		{
		case 0:
			lum0 = sinf(hi.pos.y() * scale.y() * (PI / 2));
			lum1 = sinf(hi.pos.z() * scale.z() * (PI / 2));
			break;
		case 1:
			lum0 = sinf(hi.pos.x() * scale.x() * (PI / 2));
			lum1 = sinf(hi.pos.z() * scale.z() * (PI / 2));
			break;
		case 2:
			lum0 = sinf(hi.pos.x() * scale.x() * (PI / 2));
			lum1 = sinf(hi.pos.y() * scale.y() * (PI / 2));
			break;
		}

		float ol = lum0 * lum1 / 2 + 0.5;
		if (contrast) ol = (ol > 0.5) ? 1 : 0;

		return max(color * ol, darkColor * (1 - ol));
	}
};

class toonEdge : public texture
{
public:
	vec color;
	float size;
	float alpha;
	bool contrast;

	toonEdge(QString name, vec color = vec(0.8, 0.8, 0.8), float size = 15, float alpha = 1)
		:color(color), size(size), alpha(alpha), contrast(true) {
		this->name = name; type = texType::TEG;
	}
	toonEdge(QString name, QColor color, float size = 15, float alpha = 1)
		:color(color2vec(color)), size(size), alpha(alpha), contrast(true) {
		this->name = name; type = texType::TEG;
	}

	vec value(const vec2& uv, const hitInfo& hi, const Ray& ray)const {
		float lum0 = acosf(vec::dotProduct((ray.dir * -1).normalized(), hi.normal));

		lum0 = lum0 > (90 - size) * DEG2RAD ? (1 - alpha) : 1;

		return color * lum0;
	}
};

extern texture* defaultTex;

extern QList<texture*> texList;
